package com.example.mykotlin.base.util

import com.example.mykotlin.base.result.R
import com.example.mykotlin.base.result.ServiceException
import com.example.mykotlin.service.BatchSelectFuture
import com.example.mykotlin.service.BigBatchSelectFuture
import com.mybatisflex.annotation.Column
import com.mybatisflex.core.row.Db
import com.mybatisflex.kotlin.extensions.db.baseMapper
import com.mybatisflex.kotlin.extensions.db.baseMapperOrNull
import com.mybatisflex.kotlin.extensions.db.tableInfo
import com.mybatisflex.kotlin.extensions.model.toRow
import java.io.Serializable
import kotlin.reflect.KProperty
import kotlin.reflect.full.declaredMemberProperties

/**
 * 简化try-catch代码块的书写，并接受方法体的返回值，可设置异常时的默认值
 * @param def 异常时的默认值
 * @param block 执行的方法体
 */
inline fun <R> tryReturn(def: R? = null, block: () -> R): R? {
    return try {
        block()
    } catch (_: Exception) {
        return def
    }
}

/**
 * 简化try-catch代码块的书写，不抛出异常
 * @param block 执行的方法体
 */
inline fun tryOnly(block: () -> Unit) {
    try {
        block()
    } catch (_: Exception) {
    }
}

/**
 * 简化Service层，不用再定义生成多个service类
 * @param cacheKey 使用本地缓存，缓存的key，不传递则不使用
 * @param service service需要执行的方法逻辑
 */
inline fun <T, reified K : Any> T.runService(cacheKey: String? = null, crossinline service: () -> K?): R<K> {
    val hasAuditLong = AuditLogAspect.AUDIT_LOG_DATA_INFO.get() != null
    return try {
        val r = if (cacheKey != null) {
            GetBean.commonService()
                .localCache(this!!::class.java.name, cacheKey) { if (hasAuditLong) tr { service() } else service() }
        } else {
            if (hasAuditLong) tr { service() } else service()
        }
        return if (r is R<*>) r as R<K> else R.ok(r)
    } catch (se: ServiceException) {
        R.LOG.warn("服务请求成功，业务异常:", se)
        R.fail(code = se.code, msg = se.message ?: "服务请求成功，业务异常")
    } catch (re: RuntimeException) {
        R.LOG.error("运行时异常:", re)
        R.fail(msg = "运行时异常:${re.javaClass.simpleName}")
    } catch (e: Exception) {
        R.LOG.error("异常:", e)
        R.fail(msg = "异常:${e.javaClass.simpleName}")
    }
}

/**
 * 简化Service层，并给service服务添加事务，去除了service层的补充
 * @param service service需要执行的方法逻辑
 */
inline fun <T, reified K : Any> T.runServiceWithTransaction(cacheKey: String? = null, crossinline service: () -> K?) =
    try {
        val r = if (cacheKey != null) {
            GetBean.commonService().localCache(this!!::class.java.name, cacheKey) { tr { service() } }
        } else {
            tr { service() }
        }
        if (r is R<*>) r as R<K> else R.ok(r)
    } catch (se: ServiceException) {
        R.LOG.warn("服务请求成功，业务异常:", se)
        R.fail(code = se.code, msg = se.message ?: "服务请求成功，业务异常")
    } catch (re: RuntimeException) {
        R.LOG.error("运行时异常:", re)
        R.fail(msg = "运行时异常:${re.javaClass.simpleName}")
    } catch (e: Exception) {
        R.LOG.error("异常:", e)
        R.fail(msg = "异常:${e.javaClass.simpleName}")
    }

/**
 * 编程式事务的一种方式实现，去除了service层的补充
 * @param service service需要执行的方法逻辑
 */
inline fun <reified R : Any> tr(noinline service: () -> R?) = GetBean.commonService().executeTransaction(service)

inline fun <reified R : Any> trNotThrow(noinline service: () -> R?) = try {
    tr(service)
} catch (_: Exception) {
    null
}

/**
 * mybatis-flex select方法使用的补充，排除要查询表的字段
 */
inline fun <reified E : Any> except(vararg properties: KProperty<*>): Array<KProperty<*>> {
    val ignoreField = mutableSetOf<String>()
    E::class.java.declaredFields.forEach {
        val column: Column? = it.getAnnotation(Column::class.java)
        if (column?.ignore == true) {
            ignoreField.add(it.name)
        }
    }
    val list = E::class.declaredMemberProperties.filter {
        !ignoreField.contains(it.name)
    }.filter { !properties.contains(it as KProperty<*>) }.toList()
    return Array(list.size) { list[it] }
}

/**
 * 分布式锁的简单写法
 * @param lockKey 分布式锁名称
 * @param waitTime 获取锁的等待时间,单位秒
 * @param leaseTime 获取锁后持有锁的最大时间,单位秒
 * @param service service需要执行的方法逻辑
 */
inline fun <reified E : Any> lockService(
    lockKey: String?, waitTime: Long, leaseTime: Long, crossinline service: () -> E?
): E? {
    val getLock = RedissonUtil.tryLockAndGetLock(lockKey, waitTime, leaseTime)
    try {
        return if (getLock.second) service() else null
    } finally {
        RedissonUtil.unlock(getLock.first)
    }
}

/**
 * 根据id修改一条数据
 * @param entity 实体对象
 */
inline fun <reified E : Any> updateById(entity: E) =
    E::class.baseMapperOrNull?.update(entity) ?: E::class.tableInfo.let {
        Db.updateById(it.schema, it.tableName, entity.toRow())
    }

/**
 * 根据id查询一条数据
 * @param entity 实体对象
 */
inline fun <reified E : Any> selectById(id: Serializable): E? = selectByIdBatch<E>(id).getById(id)

/**
 * 根据id查询一条数据(批量Future模式)
 * @param entity 实体对象
 */
inline fun <reified E : Any> selectByIdBatch(id: Serializable): BatchSelectFuture<E> {
    return BatchSelectFuture.select(E::class, E::class.baseMapper, id)
}

inline fun <reified E : Any> selectByIdBigBatch(id: Serializable): BigBatchSelectFuture<E> {
    return BigBatchSelectFuture.select(E::class, E::class.baseMapper, id)
}


